package org.tigris.atlas.xml.schema.mda.generator;

import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.apache.velocity.VelocityContext;
import org.tigris.atlas.mda.generator.AbstractResourcesGenerator;
import org.tigris.atlas.mda.generator.GenerationContext;
import org.tigris.atlas.mda.generator.GenerationException;
import org.tigris.atlas.mda.metadata.MetadataRepository;
import org.tigris.atlas.mda.metadata.element.Operation;
import org.tigris.atlas.mda.metadata.element.Service;
import org.tigris.atlas.xml.schema.mda.element.SchemaElementUtils;
import org.tigris.atlas.xml.schema.mda.element.SchemaOperation;
import org.tigris.atlas.xml.schema.mda.element.SchemaService;

public abstract class AbstractSchemaServiceResponseGenerator extends AbstractResourcesGenerator {

	private static final String TAG_RETURN_MANY_TYPE_NAME = "${returnManyTypeName}";
	protected static final String TAG_OPERATION_NAME = "${operationName}";	
	
	public void generate(GenerationContext context) throws GenerationException {
		String applicationName = context.getArtifactId();
		Iterator serviceIterator = MetadataRepository.getInstance().getAllServices(applicationName).values().iterator();
		
		Service service;
		SchemaService schemaService;
		SchemaOperation schemaOperation;
		Iterator operationIterator;
		String fileName;
		VelocityContext vc;
		String basefileName = context.getOutputFile();		
		basefileName = replaceBasePackage(basefileName, context.getBasePackageAsPath());
		while (serviceIterator.hasNext()) {
			service = (Service) serviceIterator.next();
			schemaService = new SchemaService(service);
			
			
			operationIterator = schemaService.getOperations().values().iterator();
			while(operationIterator.hasNext()) {
				schemaOperation = (SchemaOperation)operationIterator.next();
				
				if (shouldGenerate(schemaOperation)) {
					vc = setupContext(context, schemaService, schemaOperation);
					
					if (StringUtils.contains(basefileName, TAG_OPERATION_NAME)) {
						fileName = replaceOperationName(basefileName, schemaOperation.getName());
					} else {
						fileName = replaceReturnManyTypeName(basefileName, schemaOperation.getReturnManyType());
					}
					context.setOutputFile(fileName);
					
					generateFile(context, vc);
					
				}				
			}
		}
	}
	
	/**
	 * Provides an opportunity to add specific response data into the context
	 * @param context
	 * @param schemaService
	 * @param schemaOperation
	 * @return
	 */
	protected VelocityContext setupContext(GenerationContext context, Service service, Operation operation) {
		VelocityContext vc;
		vc = new VelocityContext();
		vc.put("service", service);
		vc.put("operation", operation);
		
		String baseNamespace = SchemaElementUtils.translateBasePackageToBaseSchemaLocation(context.getBasePackage());
		vc.put("baseNamespace", baseNamespace);
		
		return vc;
	}	
	
	protected String getOutputSubFolder() {
		return OUTPUT_SUB_FOLDER_RESOURCES;
	}
	
	protected final String replaceOperationName(String original, String operationName) {
		return StringUtils.replace(original, TAG_OPERATION_NAME, operationName);
	}
	
	protected final String replaceReturnManyTypeName(String original, String returnManyTypeName) {
		return StringUtils.replace(original, TAG_RETURN_MANY_TYPE_NAME, returnManyTypeName);
	}
	
	protected boolean isSingleEntityResponse(Operation operation) {
		return (MetadataRepository.getInstance().getEntity( operation.getReturnType() ) != null);
	}

	protected boolean isCollectionResponse(Operation operation) {
		return operation.getReturnManyType() != null;
	}	
	
	/**
	 * Determine if this operation should result in the generation of a service response
	 * @param operation The operation in question
	 * @return the result
	 */
	protected abstract boolean shouldGenerate(Operation operation);	

}
